package com.ncmmall.mall.controller.securitys;

import com.ncmmall.application.securitys.logs.OperationLogApplication;
import com.ncmmall.application.securitys.navigation.NavigationApplication;
import com.ncmmall.mall.controller.securitys.shiro.Securitys;
import com.ncmmall.mall.params.LayUiData;
import com.feijin.commons.exceptions.IllegalRequestException;
import com.feijin.commons.webs.Webs;
import com.ncmmall.domain.security.auth.Authority;
import com.ncmmall.domain.security.auth.QAuthority;
import com.ncmmall.domain.security.nav.Navigation;
import com.ncmmall.domain.security.nav.QNavigation;
import com.ncmmall.domain.security.page.Page;
import com.ncmmall.domain.security.page.Permission;
import com.ncmmall.domain.security.page.QPermission;
import com.ncmmall.domain.security.role.QRole;
import com.ncmmall.domain.security.role.Role;
import com.ncmmall.domain.security.user.WebUser;
import com.ncmmall.querychannel.QueryPage;
import com.ncmmall.querychannel.QueryPageRequest;
import com.ncmmall.querychannel.service.QueryChannelService;
import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author tongchun
 *         菜单配置
 */
@Controller
@RequestMapping(value = "/securitys/nav")
public class NavigationController {

    private final static Logger LOG = LoggerFactory.getLogger(NavigationController.class);

    @Autowired
    private QueryChannelService queryChannelService;

    @Autowired
    private NavigationApplication navApplication;

    @Autowired
    private OperationLogApplication logApplication;

    @Value("${web.domain}")
    private String webDomain;

    /**
     * 加载角色菜单
     *
     * @param model
     * @param id
     * @return
     */
    @RequestMapping(value = "/{id}/navigation", method = RequestMethod.GET)
    private String navigation(Model model, @PathVariable("id") long id) {

        List<Navigation> result = queryChannelService.findAll("select n from Navigation n where n.role.id =:id and n.parent is null order by n.rank desc ", ImmutableMap.of("id", id), Navigation.class);
        JSONArray nodes = new JSONArray();
        for (Navigation nav : result) {

            JSONObject item = new JSONObject();
            item.put("id", String.valueOf(nav.getId()));
            item.put("title", nav.getTitle());
            item.put("feijinIcon", nav.getIcon());

            List<Navigation> children = nav.getChildren();
            JSONArray childNodes = new JSONArray();
            for (Navigation child : children) {
                JSONObject childItem = new JSONObject();
                childItem.put("id", String.valueOf(child.getId()));
                childItem.put("title", child.getTitle());
                childItem.put("feijinIcon", child.getIcon());
                childNodes.add(childItem);


            }

            item.put("children", childNodes);
            nodes.add(item);

        }

        model.addAttribute("navigation", nodes.toString());
        model.addAttribute("role", queryChannelService.findOne(QRole.role.id.eq(id), Role.class));

        return "securitys/nav/navigation";
    }

    /**
     * 添加子菜单页面
     *
     * @param model
     * @param id
     * @return
     */
    @RequestMapping(value = "/{id}/createChild", method = RequestMethod.GET)
    private String createChild(Model model, @PathVariable("id") long id) {
        Navigation nav = new Navigation();
        nav.setRole(queryChannelService.findOne(QNavigation.navigation.id.eq(id), Navigation.class).getRole());
        nav.setParent(queryChannelService.findOne(QNavigation.navigation.id.eq(id), Navigation.class));
        model.addAttribute("_method", "POST").addAttribute("nav", nav);
        return "securitys/nav/form";
    }

    /**
     * 添加子菜单
     *
     * @param nav
     * @return
     */
    @RequestMapping(value = "/{id}/createChild", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> createChild(HttpServletRequest request, Navigation nav) {

        navApplication.create(nav);
        iniUserAuthoritysInSession(Securitys.currentUser());

        logApplication.eventOfSystem(Securitys.currentUser(), "添加菜单" + nav.getTitle(), Securitys.getIp(request));

        return ImmutableMap.of("status", true);
    }

    /**
     * 添加一级菜单页面
     *
     * @param model
     * @param id
     * @return
     */
    @RequestMapping(value = "/{id}/create", method = RequestMethod.GET)
    private String create(Model model, @PathVariable("id") long id) {
        Navigation nav = new Navigation();
        nav.setRole(queryChannelService.findOne(QRole.role.id.eq(id), Role.class));
        model.addAttribute("_method", "POST").addAttribute("nav", nav);

        return "securitys/nav/form";
    }

    /**
     * 添加一级菜单
     *
     * @param nav
     * @return
     */
    @RequestMapping(value = "/{id}/create", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> create(HttpServletRequest request, Navigation nav) {

        navApplication.create(nav);
        iniUserAuthoritysInSession(Securitys.currentUser());

        logApplication.eventOfSystem(Securitys.currentUser(), "添加菜单" + nav.getTitle(), Securitys.getIp(request));

        return ImmutableMap.of("status", true);
    }

    /**
     * 编辑菜单页面
     *
     * @param model
     * @param id
     * @return
     */
    @RequestMapping(value = "/{id}/edit", method = RequestMethod.GET)
    private String edit(Model model, @PathVariable("id") long id) {
        Navigation nav = queryChannelService.findOne(QNavigation.navigation.id.eq(id), Navigation.class);
        List<Authority> authorities = queryChannelService.findAll(QAuthority.authority.navigation.id.eq(nav.getId()), Authority.class);
        String authority = "";
        for (Authority item : authorities) {
            authority += item.getName();
        }

        if (null != nav.getPage()) {
            List<Permission> permissions = queryChannelService.findAll(QPermission.permission1.page.id.eq(nav.getPage().getId()), Permission.class);
            model.addAttribute("permissions", permissions);
        }

        model.addAttribute("_method", "PUT").addAttribute("nav", nav).addAttribute("authorities", authority);

        return "securitys/nav/form";
    }


    /**
     * 修改菜单
     *
     * @param model
     * @param nav
     * @return
     */
    @RequestMapping(value = "/{id}/edit", method = RequestMethod.PUT)
    @ResponseBody
    private Map<String, Object> edit(HttpServletRequest request, Model model, Navigation nav) {

        navApplication.modify(nav);
        iniUserAuthoritysInSession(Securitys.currentUser());
        logApplication.eventOfSystem(Securitys.currentUser(), "编辑菜单" + nav.getTitle(), Securitys.getIp(request));
        return ImmutableMap.of("status", true);
    }

    /**
     * 修改子菜单页面跳转
     *
     * @param model
     * @param id
     * @return
     */
    @RequestMapping(value = "/{id}/editChild", method = RequestMethod.GET)
    private String editChild(Model model, @PathVariable("id") long id) {
        Navigation nav = queryChannelService.findOne(QNavigation.navigation.id.eq(id), Navigation.class);
        List<Authority> authorities = queryChannelService.findAll(QAuthority.authority.navigation.id.eq(nav.getId()), Authority.class);
        String authority = "";
        for (Authority item : authorities) {
            authority += item.getName();
        }

        List<Permission> permissions = queryChannelService.findAll(QPermission.permission1.page.id.eq(nav.getPage().getId()), Permission.class);
        model.addAttribute("_method", "PUT").addAttribute("nav", nav).addAttribute("authorities", authority).addAttribute("permissions", permissions);

        return "securitys/nav/form";
    }


    /**
     * 修改子菜单
     *
     * @param model
     * @param nav
     * @return
     */
    @RequestMapping(value = "/{id}/editChild", method = RequestMethod.PUT)
    @ResponseBody
    private Map<String, Object> editChild(HttpServletRequest request, Model model, Navigation nav) {

        navApplication.modify(nav);
        iniUserAuthoritysInSession(Securitys.currentUser());

        logApplication.eventOfSystem(Securitys.currentUser(), "修改菜单" + nav.getTitle(), Securitys.getIp(request));

        return ImmutableMap.of("status", true);
    }

    /**
     * 删除菜单
     *
     * @param requestWith
     * @param id
     * @return
     */
    @RequestMapping(value = "/remove", method = RequestMethod.DELETE)
    @ResponseBody
    private Map<String, Object> remove(HttpServletRequest request, @RequestHeader("X-Requested-With") String requestWith, @RequestParam("id") long id) {
        try {

            if (!Webs.isAjaxRequest(requestWith)) {
                throw new IllegalRequestException("request must be Ajax!");
            }

            Navigation navigation = queryChannelService.findOne(QNavigation.navigation.id.eq(id), Navigation.class);

            logApplication.eventOfSystem(Securitys.currentUser(), "删除菜单" + navigation.getTitle(), Securitys.getIp(request));

            navApplication.remove(navigation);
            iniUserAuthoritysInSession(Securitys.currentUser());

        } catch (Exception e) {
            LOG.error("[权限删除异常]", e);
            return ImmutableMap.of("status", false);
        }

        return ImmutableMap.of("status", true);

    }

    /**
     * 跳转选择菜单指向的页面
     *
     * @return
     */
    @RequestMapping(value = "/route", method = RequestMethod.GET)
    private String routePage() {

        return "securitys/nav/routePage";
    }

    /**
     * 加载页面所拥有的全部权限
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/permission", method = RequestMethod.GET)
    @ResponseBody
    private Map<String, Object> permission(@RequestParam("id") long id) {
        List<Permission> permissions = queryChannelService.findAll(QPermission.permission1.page.id.eq(id), Permission.class);
        for (Permission permission : permissions) {
            permission.setPage(null);
        }
        return ImmutableMap.of("status", true, "result", permissions);
    }

    /**
     * 加载所有页面供菜单选择
     *
     * @param pageNo
     * @param pageSize
     * @param keyword
     * @return
     */
    @RequestMapping(value = "/paths")
    @ResponseBody
    private LayUiData teachers(@RequestParam("page") int pageNo, @RequestParam("limit") int pageSize, @RequestParam("keyword") String keyword) {

        LayUiData data = new LayUiData();

        QueryPageRequest pageRequest = new QueryPageRequest().setPageNo(pageNo).setPageSize(pageSize);
        String hql = "select u from Page u where 1=1 ";

        if (!Strings.isNullOrEmpty(keyword)) {
            pageRequest.setParams(ImmutableMap.of("keyword", "%" + keyword + "%"));
            hql += " and u.name like :keyword  ";
        }

        hql += " order by u.id desc ";

        QueryPage<Page> page = queryChannelService.findPage(hql, pageRequest, Page.class);
        page.setResult(Lists.transform(page.getResult(), new Function<Page, Page>() {
            @Nullable
            @Override
            public Page apply(@Nullable Page input) {
                input.setPermissions(null);
                return input;
            }
        }));
        List<Page> paths = page.getResult();
        data.setCode(0);
        data.setMsg("");
        data.setCount((int) page.getTotalCount());
        data.setData(paths);

        return data;

    }

    /**
     * 初始化用户拥有的角色及角色所拥有的所有权限，写入session
     *
     * @param user
     */
    private void iniUserAuthoritysInSession(WebUser user) {


        List<Role> roles = queryChannelService.findAll("select r from Role  r where r.id = :id", ImmutableMap.of("id", user.getRole().getId()), Role.class);
        List<Authority> authorities = queryChannelService.findAll("select a from Authority a where a.id in (select r.authoritysId from RoleAuthority r where roleId = :roleId)", ImmutableMap.of("roleId", user.getRole().getId()), Authority.class);

        Set<String> roleNames = Sets.newHashSet();
        for (Role role : roles) {
            roleNames.add(role.getName());
        }

        Set<String> permissions = Sets.newHashSet();
        for (Authority authority : authorities) {
            permissions.add(authority.getPermission());
        }

        Securitys.getSession().setAttribute("shiro_roles", roleNames);
        Securitys.getSession().setAttribute("shiro_permission", permissions);

    }


}
